iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
自我挑戰組

JavaScript101與人生幹話系列 第 25

JavaScript101與人生幹話-比較詳細一點的物件說明

  • 分享至 

  • xImage
  •  

物件

1-1物件原來還可以這樣寫

// 使用變數加字串取值
let myName = 'name'

const obj = {
    name: 'Jack'
}
console.log(obj[myName]) // 'Jack'
console.log(obj.name) // 'Jack'

注意在JS中物件的屬性都是字串。

如何增加/刪除屬性

const obj = {
    name: 'Jack',
    location: 'Taipen',
    money: 50000,
    age:25
}
// 增加一個gender: 'male'
obj.gender = 'male'
console.log(obj) 
//{
//    name: 'Jack',
//    location: 'Taipen',
//    money: 50000,
//    age:25
//}
// 刪除一個屬性
delete obj.money
// 或
delete obj['money']
console.log(obj)
//{
//    name: 'Jack',
//    location: 'Taipen',
//    age:25
//}

1-2變數及物件屬性的差異

屬性可以刪除,變數不能刪除

var a = 1
b = 2
console.log(window)
// 會發現有一個變數a : 1
// 與變數b:2
// 但是
delete a
delete b 
console.log(a) // 1
console.log(b) // b is not defined

1-3物件與純值

純值無法新增屬性

var string = 'a'
string.name = 'Jack'
console.log(string.name) // undefined

var newString = new String('a')
newString.name = 'Jack'
console.log(newString) // String {'a', name: 'Jack'}

因為建構式所產生的是物件,所以可以增加屬性。

1-3-1函式也是物件

function callMyName() {
    console.log('Jack')
}
callMyName.Jack = 'Jack'
// 不能用callMyName.name,因為這個屬性是這個含式的名子無法被修改,類似保留字的概念
console.dir(callMyName) //ƒ callMyName()
console.log(callMyName.Jack) // 'Jack'  

1-4未定義的物件屬性預設值

不能在undefined下定義屬性

const obj = {
    name: 'Jack'
}
obj.family.mon = 'May'
console.log(obj.family.mon) // Uncaught TypeError: Cannot set properties of undefined (setting 'mon')

如何解決呢?

// 方法一 先定義好物件結構
const obj = {
    name: 'Jack',
    family: {}
}
obj.family.mon = 'May'
console.log(obj.family.mon)// 'May'
// 方法二 直接加上屬性
const obj = {
    name: 'Jack',
}
obj.family = {
    mon: 'May'
}
console.log(obj.family.mon)// 'May'

1-5物件的參考特性(value and reference)

var obj = {
    name: 'Jack'
}
var obj2 = obj
obj2.name = 'Rose'
console.log(obj.name) // 'Rose'

會發生這種情況是因為,變數儲存的參考位置,立如下圖的0x01

圖片來源:六角學院JS核心篇
在修改時等於obj2.name = 'Rose'時如下圖,因為指向相同所以修改obj2也等同修改obj


圖片來源:六角學院JS核心篇
但如果變數被指向另一個物件則變數儲存的參考位置改變了,如下圖

圖片來源:六角學院JS核心篇

var obj = {
    name: 'Jack'
}
var obj2 = obj
obj2 = {
   name: 'Jack'
}
console.log(obj === obj2) // false

會出現雖然兩個物件的值相等,但因為參考位置不同而得到false的結果。

最後圖解如何傳址

題目1

var a = {x:1}
var b = a
a.y = a = {x:2}
console.log(a.y)
console.log(b)

步驟1
物件{x:1}參考位置0x01,且變數a儲存參考位置0x01,又 var b = a 所以 變數b也儲存了參考位置0x01
如下圖

步驟2
物件{x:2}參考位置0x02,變數a的所儲存的參考位置為0x02,因為a.y = a = {x:2}可以看做是 a.y = {x:2}與 a = {x:2} 兩個同時發生,
所以在參考位置0x01產生y屬性,值為指向參考位置0x02
如下圖

最後推斷出console.log(a.y) a變數指向0x02,但是0x02沒有屬性y 所以結果為undefined。
console.log(b) 變數b指向0x01 為{x:1, y:指向0x02}}最後結果{x:1, y:{x:2}}

題目2

var a = { x: 1};
var b = a;
a.x = { x: 2};
a.y = a = { y: 1};
console.log(a); 
console.log(b);

步驟1
物件{x:1} 參考位置0x01,屬性X,值為1
變數a與變數b記住參考位置0x01
如下圖

步驟2
物件{ x: 2}參考位置0x02,屬性X,值為2
又因為a.x為參考位置0x01中的x屬性,所以0x01中的x屬性指向了0x02
如下圖

步驟3
物件{y:1}參考位置0x03,屬性y,值為1
a = {y:1}代表變數a的指向改為0x03,同時又因為a.y會在參考位置0x01的地方產生一個屬性y,值指向參考位置0x03,可以把a.y = a = {y:1}看做a = {y:1} 與 a.y = {y:1}且同時發生。
如下圖

最後console.log(a) 指向參考位置0x03 {y:1}
console.log(b)指向參考位置0x01 {x:指向參考位置0x02, y:指向參考位置0x03} => {x:{x:2}, {y:{y:1}}}

1-6淺層複製及深層複製

淺拷貝只能複製物件但是物件內的物件依舊會傳參考
例如:

var obj = {
  name: 'Jack',
  family: {
    mon:'May',
    dad:'John'
  }
}
var obj2 = {}
for (let key in obj) {
  obj2[key] = obj[key]
}
// obj2複製obj
obj2.name = 'Jay'
console.log('obj2', obj2)
//{
//  name: 'Jay',
//  family: {
//    mon:'May',
//    dad:'John'
//  }
//}

obj2.family.dad='Kven'
// 可以發現到雖然obj2修改了faily的物件,但是obj內的物件也跟著修改了。
console.log('obj', obj)
//{
//  name: 'Kven',
//  family: {
//    mon:'May',
//    dad:'John'
//  }
//}

以下是前拷貝的方法

// jQuery extend
var obj3 = jQuery.extend({}, obj)
console.log('obj3', obj3)
// ES6
var obj4 = Object.assign({}, obj)
console.log('obj4', obj4)
// 擴展
var obj5 = {...obj}
console.log('obj5',obj5)


深拷貝,把物件字串話之後在解析回物件並賦值在新變數上,這樣子深層的物件修改也會與原本的物件無關。

var obj6 = JSON.parse(JSON.stringify(obj))
obj6.family.dad = 'Smith'
console.log('obj6', obj6)

淺層複製及深層複製範例的程式碼連結

[JS物件的深拷貝與淺拷貝](https://codepen.io/efzdamnp-the-lessful/pen/mdxdmXv?editors=0011

1-7陣列

陣列是一種物件,不過有自己的讀取與刪除方式。

let arr = ['a', 1, true, {name:'Jack'}, ['123']]
// 讀出物件的第X個值,注意陣列的第X個是從0開始算
console.log(`這是物件的第3個值為:${arr[2]}`)

// 增加值到陣列的最後面
arr.push('我是被後來加上的')
console.log(arr[5]) // "我是被後來加上的"

// 可以指定位置增加值
arr[10] = "10"
// 注意從第6個開始到第9個會被自動加上empt,透過arr[8]讀會出現undefined
console.log(arr) // 可以看到多出很多,

// 陣列的刪除
arr.splice(2, 1)
console.log(arr) // 可以看到第三個true被刪除了

以上範例連結

延伸閱讀

關於 JavaScript 陣列 20 種操作的方法

1-8JSON

JSON與JS的物件很類似但不是同一個東西。
JSON格式的key 與 value 都必須使用雙引號且格式全部都是字串。

{
    "name": "Jack",
    "age": "25",
    "location": "Taipei",
    "member": {
        "dad": "John",
        "mon": "May"
    }
}

人生幹話-原來我是抓耙仔

第二年開始,奇怪的事情就越來越多了,除了要進版與維護法規文件外還要負責各地單位間的溝通之外就是與各單位討論風險管理,一開始風險管理討論還蠻正常的,剛開始的討論頻率是一周一次,也很快的完成出版的風險管理表格,在半年之後因為產品的開發進入瓶頸期自然也不會有很多的原因要分析,這個時候就需要調整開會頻率,可以修改為一個月一次,我向主管提出把重點放在文件的更新與競品資料的蒐集分析,也就在這個時候我開始自學python,不只是想自己的東西,另外可以優化資料蒐集與分析而不是沒意義的重複會議,大主管表示要站在老闆的立場思考,風險管理只是附加的東西,我們是幫老闆盯進度,搞了這麼久原來我的工作不是做風險管理,是抓耙仔


上一篇
JavaScript101與人生幹話-執行環境、作用域
下一篇
JavaScript101與人生幹話-函式、閉包、This與simple call
系列文
JavaScript101與人生幹話30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言